﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Reflection;
using System.ServiceModel;
using System.Windows.Forms;
using DM4;
using DevExpress.XtraBars.Helpers;
using DevExpress.XtraBars.Ribbon;
using sscore;
using System.Runtime.Serialization;
using System.Xml;
using System.Diagnostics;
using UrielGuy.SyntaxHighlightingTextBox;
using System.Threading.Tasks;
using System.Threading;
using sscore.Utils;
using DM4.InfoClasses;
using System.Linq;
using System.Globalization;
using DevExpress.XtraTreeList.Nodes;

namespace DM4Client
{
    public partial class FrmMain : RibbonForm
    {
        private const string _version = "1.5";

        public static DM4.DM4 Server;
        public static ServiceReferenceLog.Entities LogEntities;

        public static Configuration Config = ConfigurationManager.OpenExeConfiguration(
        ConfigurationUserLevel.None);

        private Task _wait;
        private CancellationTokenSource _waitCTS;
        private int _waitRequestCount;

        public static Params ServerParams;
        public static Log ServerLog;
        public static ServiceHost ServerHost;
        public static SqlConnection ServerDBConnection;
        public static LogDataClassesDataContext LogDataClasses;

        public static Log Log;
        public static Params Prm;
        public static String WorkDir = Path.GetDirectoryName(Application.ExecutablePath);
        public static ChannelFactory<IDM4> Dm4ChannelFactory;
        public static ChannelFactory<IDM4Core> Dm4CoreChannelFactory;
        public static IDM4 Dm4Srv;
        public static IDM4Core Dm4Core;

        public static IDictionary<string, string> Srvnames = new Dictionary<string, string>();

        public static DataTable DtGroups = new DataTable();
        public static DataTable DtModules = new DataTable();
        public static DataTable DtScripts = new DataTable();
        public static DataTable DtWork = new DataTable();
        public static DataTable DtMailSendTemplates = new DataTable();
        public static DataTable DtMailAccounts = new DataTable();

        public static DataTable DtMailSenders = new DataTable();
        public static DataTable DtLetters = new DataTable();
        public static DataTable DtMailRules = new DataTable();
        public static DataTable DtMailLettersRules = new DataTable();

        public static DataTable DtLog = new DataTable();

        public static bool IsAdmin;
        public static int Currentuserid;
        private static string usrSessionId;
        public static DataTable CurrentUser;

        private readonly SyntaxHighlightingTextBox _stbGroupInfoScript;
        private readonly SyntaxHighlightingTextBox _stbScriptInfoScript;
        private readonly SyntaxHighlightingTextBox _stbScriptLog;

        private readonly SyntaxHighlightingTextBox _stbMailSendTemplateSubject;
        private readonly SyntaxHighlightingTextBox _stbMailSendTemplateBody;

        private readonly DM4Client.GridForms.FrmGroups _fGroups = new DM4Client.GridForms.FrmGroups();
        private readonly DM4Client.GridForms.FrmScripts _fScripts = new DM4Client.GridForms.FrmScripts();
        private readonly DM4Client.GridForms.FrmMailDaemons _fMails = new DM4Client.GridForms.FrmMailDaemons();
        private readonly DM4Client.GridForms.FrmWork _fWork = new DM4Client.GridForms.FrmWork();
        private readonly DM4Client.GridForms.FrmLog _fLog = new DM4Client.GridForms.FrmLog();

        private ActivePageIdx _activePageIndex;

        static public XMLInfo SetUsrSessionId(XMLInfo xi)
        {
            usrSessionId = xi.OperResult.UsrSessionId;
            if (xi.OperResult.Result == DM4Consts.ErrorServerLoading || xi.OperResult.Result == DM4Consts.ErrorServerShutdown)
                MessageBox.Show(xi.OperResult.Message, MessageType.Error.ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);

            return xi;
        }

        static public OperationResult SetUsrSessionId(OperationResult or)
        {
            usrSessionId = or.UsrSessionId;
            if (or.Result == DM4Consts.ErrorServerLoading || or.Result == DM4Consts.ErrorServerShutdown)
                MessageBox.Show(or.Message, MessageType.Error.ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
            return or;
        }

        public FrmMain()
        {
            AppDomain currentDomain = AppDomain.CurrentDomain;
            currentDomain.AssemblyResolve += ResolveEventHandler;

            Log = Log.CreateLogWithDataset(String.Format("{0}\\{1}", WorkDir, DM4ClientConst.LogFileName), EncodingType.Utf8,
            LogMode.Full, LogDatasetFillMode.TailToTop, true);

            Prm = Params.CreateNonCryptedParamsWithoutEtalon(String.Format("{0}\\{1}", WorkDir, DM4ClientConst.ClientConfigFilename));

            InitializeComponent();

            if (Prm.Exists("Skin"))
                lafDefault.LookAndFeel.SetSkinStyle(Prm.GetStringParam("Skin"));
            else
                Prm.CreateStringParam("Skin", "");

            Text = String.Format("DM4 Client {0}", _version);
            rbMain.ApplicationCaption = String.Format("DM4 Client {0}", _version);

            _stbGroupInfoScript = Common.CreateScriptEditControl(_fGroups.gcScriptText.Controls, Appearance.BackColor, true);
            _stbScriptInfoScript = Common.CreateScriptEditControl(_fScripts.gcScriptText.Controls, Appearance.BackColor, true);
            _stbScriptLog = Common.CreateScriptLogControl(_fScripts.gcLog.Controls, Appearance.BackColor);
            _stbMailSendTemplateSubject = Common.CreateMailEditTemplateControl(_fMails.gcSubject.Controls, Appearance.BackColor, true);
            _stbMailSendTemplateBody = Common.CreateMailEditTemplateControl(_fMails.gcBody.Controls, Appearance.BackColor, true);

            InitSkinGallery();

            LoginToService(true);

            ProcessWorkDirs();
        }

        private void InitGui()
        {
            pnlMain.Dock = DockStyle.Fill;

            pnlMain.Controls.Add(_fGroups.pnlMain);
            pnlMain.Controls.Add(_fScripts.pnlMain);
            pnlMain.Controls.Add(_fMails.pnlMain);
            pnlMain.Controls.Add(_fWork.pnlMain);
            pnlMain.Controls.Add(_fLog.pnlMain);

            //groups form
            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvgroups.xml")))
                _fGroups.gvGroups.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvgroups.xml"));

            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmodulehelp.xml")))
                _fGroups.gvModuleParams.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmodulehelp.xml"));

            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvgroupinfo.xml")))
                _fGroups.gvGroupInfo.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvgroupinfo.xml"));

            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmodules.xml")))
                _fGroups.gvModules.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmodules.xml"));

            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmoduleinfo.xml")))
                _fGroups.gvModuleInfo.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmoduleinfo.xml"));

            //scripts form
            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvscripts.xml")))
                _fScripts.gvScripts.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvscripts.xml"));

            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvscriptsinfo.xml")))
                _fScripts.gvScriptInfo.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvscriptsinfo.xml"));

            //mail daemons form
            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmailaccounts.xml")))
                _fMails.gvAccounts.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmailaccounts.xml"));

            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmailtemplates.xml")))
                _fMails.gvMailTemplates.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmailtemplates.xml"));


            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvsenders.xml")))
                _fMails.gvSenders.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvsenders.xml"));

            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvletters.xml")))
                _fMails.gvLetters.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvletters.xml"));

            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvallrules.xml")))
                _fMails.gvAllRules.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvallrules.xml"));

            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvletterrules.xml")))
                _fMails.gvLetterRules.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvletterrules.xml"));

            if (File.Exists(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "tlwork.xml")))
                _fWork.tlWork.RestoreLayoutFromXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "tlwork.xml"));

            //init inspector grids
            _fGroups.dgGroupInfo.DataSource = dsInfo;
            _fGroups.dgGroupInfo.DataMember = "dtGroupInfo";
            _fGroups.dgGroupInfo.KeyDown += DgInspectorsPreviewKeyDown;

            _fGroups.dgModuleParams.DataSource = dsInfo;
            _fGroups.dgModuleParams.DataMember = "dtModuleParamsHelp";
            _fGroups.dgModuleParams.KeyDown += DgInspectorsPreviewKeyDown;

            _fGroups.dgModuleInfo.DataSource = dsInfo;
            _fGroups.dgModuleInfo.DataMember = "dtModuleInfo";
            _fGroups.dgModuleInfo.KeyDown += DgInspectorsPreviewKeyDown;

            _fScripts.dgScriptInfo.DataSource = dsInfo;
            _fScripts.dgScriptInfo.DataMember = "dtScriptInfo";
            _fScripts.dgScriptInfo.KeyDown += DgInspectorsPreviewKeyDown;

            //handle enter and leave on any grid for update controls state
            _fGroups.dgGroups.Enter += GridEnterLeave;
            _fGroups.dgGroups.Leave += GridEnterLeave;

            _fGroups.dgModules.Enter += GridEnterLeave;
            _fGroups.dgModules.Leave += GridEnterLeave;

            _fScripts.dgScripts.Enter += GridEnterLeave;
            _fScripts.dgScripts.Leave += GridEnterLeave;

            //----_fMails
            _fMails.gcSenders.Enter += GridEnterLeave;
            _fMails.gcSenders.Leave += GridEnterLeave;

            _fMails.gcLetters.Enter += GridEnterLeave;
            _fMails.gcLetters.Leave += GridEnterLeave;

            _fMails.gcLetterRules.Enter += GridEnterLeave;
            _fMails.gcLetterRules.Leave += GridEnterLeave;

            _fMails.gcAllRules.Enter += GridEnterLeave;
            _fMails.gcAllRules.Leave += GridEnterLeave;

            _fMails.btnAddLetterRule.Click += btnAddLetterRuleClick;
            _fMails.btnDeleteRule.Click += btnDeleteLetterRuleClick;

            //handle tabs change on mail daemons form
            _fMails.tcMails.SelectedPageChanged += MailPageChanged;

            //handle tabs change on log daemons form
            _fLog.tcLogs.SelectedPageChanged += LogPageChanged;

            //work form
            _fWork.tlWork.BeforeExpand += tlWorkBeforeExpand;
        }

        private void DgInspectorsPreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.C)
            {
                DevExpress.XtraGrid.GridControl grid = (DevExpress.XtraGrid.GridControl)sender;
                DevExpress.XtraGrid.Views.Grid.GridView view = (DevExpress.XtraGrid.Views.Grid.GridView)grid.MainView;

                if (view.SelectedRowsCount == 0)
                    return;

                string text = "";
                for (int i = view.SelectedRowsCount - 1; i >= 0; i--)
                {
                    int row = view.GetSelectedRows()[i];
                    text += String.Format("{0}={1}{2}", view.GetRowCellDisplayText(row, view.VisibleColumns[0]), view.GetRowCellDisplayText(row, view.VisibleColumns[1]), Environment.NewLine);
                }
                Clipboard.SetText(text);
                e.Handled = true;
            }
        }

        private static void ProcessWorkDirs()
        {
            try
            {
                string dir = Path.Combine(WorkDir, "Tmp");

                if (Directory.Exists(dir))
                    Directory.Delete(dir, true);

                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);

                dir = Path.Combine(WorkDir, "Settings");

                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);
            }
            catch (Exception ex)
            {
                WriteError(ex.Message);
            }
        }

        void InitSkinGallery()
        {
            SkinHelper.InitSkinGallery(rgbiSkins, true);
        }

        private void FrmMainShown(object sender, EventArgs e)
        {
            BeginWait();
            try
            {
                rbMain.ShowToolbarCustomizeItem = false;
                Text = String.Format("DM4 Client {0}", _version);

                InitGui();

                lblServer.Caption = String.Format("Server: {0}", Prm.GetStringParam(PrmKeys.LastServer));

                rbiAdmin.Enabled = IsAdmin;
                rbiAdmin.Down = IsAdmin;

                rbiWorkAdminMode.Enabled = IsAdmin;
                rbiWorkAdminMode.Down = IsAdmin;

                UpdateStatus();

                rbMain.SelectedPage = rbMain.Pages[0];
                SetActiveTab();

                SetSplitters();
            }
            finally
            {
                EndWait();
            }
        }

        public static void WriteServerLog(string message, MessageType messageType = MessageType.Info)
        {
            ServerLog.WriteLog(message, messageType);
        }

        public static bool CreateServerChannel(string endpointAddress, bool builtInServer = false)
        {
            try
            {
                LogEntities = new DM4Client.ServiceReferenceLog.Entities(new Uri(String.Format("{0}LOG", endpointAddress)));

                if (builtInServer)
                {
                    Dm4Srv = Server;
                    Dm4Core = Server;
                }
                else
                {
                    BasicHttpBinding bhb = new BasicHttpBinding()
                    {
                        MaxReceivedMessageSize = 2147483647,
                        MaxBufferSize = 2147483647,
                        ReaderQuotas = { MaxStringContentLength = 2147483647 }
                    };
                    Dm4ChannelFactory = new ChannelFactory<IDM4>(
                    bhb,
                    new EndpointAddress(endpointAddress));

                    Dm4CoreChannelFactory = new ChannelFactory<IDM4Core>(
                    bhb,
                    new EndpointAddress(String.Format("{0}/{1}", endpointAddress, "Core")));

                    Dm4Srv = Dm4ChannelFactory.CreateChannel();
                    Dm4Core = Dm4CoreChannelFactory.CreateChannel();
                }
            }
            catch (Exception ex)
            {
                WriteError(ex.Message);
                MessageBox.Show(ex.Message, MessageType.Error.ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            return true;
        }

        public static void WriteError(string error)
        {
            if (Dm4Core != null)
                //DMN_Log
                Dm4Core.WriteLog(logType: LogType.System, sessId: usrSessionId, usrId: Currentuserid, message: error, messType: MessageType.Error, modCode: "FrmMain");
            else if (Log != null)
                Log.WriteLog(error, MessageType.Error);

        }

        private Assembly ResolveEventHandler(object sender, ResolveEventArgs args)
        {
            //This handler is called only when the common language runtime tries to bind to the assembly and fails.

            //Retrieve the list of referenced assemblies in an array of AssemblyName.
            string strTempAssmbPath = "";

            Assembly objExecutingAssemblies = Assembly.GetExecutingAssembly();
            AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();

            //Loop through the array of referenced assembly names.
            foreach (AssemblyName strAssmbName in arrReferencedAssmbNames)
            {
                //Check for the assembly names that have raised the "AssemblyResolve" event.
                if (strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(",", StringComparison.Ordinal)) == args.Name.Substring(0, args.Name.IndexOf(",", StringComparison.Ordinal)))
                {
                    //Build the path of the assembly from where it has to be loaded.				
                    strTempAssmbPath = String.Format("{0}\\{1}.dll", WorkDir, args.Name.Substring(0, args.Name.IndexOf(",", StringComparison.Ordinal)));
                    break;
                }
            }
            //Load the assembly from the specified path. 					
            Assembly myAssembly = Assembly.LoadFrom(strTempAssmbPath);

            //Return the loaded assembly.
            return myAssembly;
        }

        private void LoginToService(bool firstStart = false)
        {
            tmUpdateStatus.Enabled = false;

            FrmMain _fMain = firstStart ? null : this;
            try
            {
                //check param existing
                if (!Prm.Exists(PrmKeys.LastServer))
                    Prm.CreateStringParam(PrmKeys.LastServer, "");
                if (!Prm.Exists(PrmKeys.LastUser))
                    Prm.CreateStringParam(PrmKeys.LastUser, "");
                if (!Prm.Exists(PrmKeys.ServerHome))
                    Prm.CreateStringParam(PrmKeys.ServerHome, "");

                using (FrmLogin login = new FrmLogin(_fMain))
                {
                    DataContractSerializer serializer = new DataContractSerializer(Srvnames.GetType());

                    using (XmlTextReader reader = new XmlTextReader(String.Format("{0}\\{1}", WorkDir, DM4ClientConst.ServerListFileName)))
                    {
                        Srvnames = (Dictionary<string, string>)serializer.ReadObject(reader);
                    }

                    login.cbServer.Properties.Items.Clear();

                    int lastserver = -1;
                    foreach (var key in Srvnames.Keys)
                    {
                        login.cbServer.Properties.Items.Add(key);
                        if (key == Prm.GetStringParam(PrmKeys.LastServer))
                        {
                            lastserver = login.cbServer.Properties.Items.Count - 1;
                        }
                    }

                    login.tbUser.Text = Prm.GetStringParam(PrmKeys.LastUser);
                    login.cbServer.SelectedIndex = lastserver;

                    login.tbHome.Text = Prm.GetStringParam(PrmKeys.ServerHome);

                    DialogResult dr = login.ShowDialog();


                    Prm.SetStringParam(PrmKeys.LastUser, login.tbUser.Text);
                    Prm.SetStringParam(PrmKeys.LastServer, login.cbServer.Text);
                    Prm.SetStringParam(PrmKeys.ServerHome, login.tbHome.Text);

                    Prm.Save();

                    if (dr == DialogResult.Cancel)
                        Process.GetCurrentProcess().Kill();

                    IsAdmin = (AccessLevel)SysUtils.ConvertFromDBVal<int>(CurrentUser.Rows[0][CnUsers.UsrAccessLevel]) == AccessLevel.Admin;
                    Currentuserid = SysUtils.ConvertFromDBVal<int>(CurrentUser.Rows[0][CnUsers.UsrId]);
                    usrSessionId = SysUtils.ConvertFromDBVal<Guid>(CurrentUser.Rows[0][CnUsers.UsrSessionId]).ToString();
                }//using (FrmLogin login = new FrmLogin())

                tmUpdateStatus.Enabled = true;
            }
            catch (Exception ex)
            {
                WriteError(ex.Message);
            }
        }

        private void UpdateStatus()
        {
            try
            {
                GlobalInfo gi = Dm4Srv.GetInfo();
                lblVersion.Caption = String.Format("DM Version: {0}", gi.Version);
                lblWorkTime.Caption = String.Format("Work time: {0} d. {1} h. {2} m. ", gi.StartupTime.Days, gi.StartupTime.Hours, gi.StartupTime.Minutes);
                lblUser.Caption = String.Format("User: {0}", SysUtils.ConvertFromDBVal<string>(CurrentUser.Rows[0][CnUsers.UsrFullname]));

                NumberFormatInfo nfi = new CultureInfo("en-US", false).NumberFormat;
                nfi.NumberDecimalSeparator = ",";

                lblTraffic.Caption = String.Format("Total Traffic: {0} Mb", gi.Traffic.ToString("0.00", nfi));
            }
            catch (Exception ex)
            {
                //SERVER IS DOWN!! NEED RECONNECT
                WriteError(ex.Message);
                LoginToService();
            }
        }

        private void tmUpdateStatusTick(object sender, EventArgs e)
        {
            UpdateStatus();
        }

        private void SetSplitters()
        {
            //set splitters
            if (Prm != null)
            {
                //groups form
                if (!Prm.Exists(PrmKeys.SpGroupsPos))
                    Prm.CreateIntegerParam(PrmKeys.SpGroupsPos, _fGroups.spGroupInfo.SplitterPosition);
                else
                    _fGroups.spGroupInfo.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpGroupsPos);

                if (!Prm.Exists(PrmKeys.SpMainPos))
                    Prm.CreateIntegerParam(PrmKeys.SpMainPos, _fGroups.spGroups.SplitterPosition);
                else
                    _fGroups.spGroups.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpMainPos);

                if (!Prm.Exists(PrmKeys.SpGroupDescriptionPos))
                    Prm.CreateIntegerParam(PrmKeys.SpGroupDescriptionPos, _fGroups.spProjectInfo.SplitterPosition);
                else
                    _fGroups.spProjectInfo.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpGroupDescriptionPos);

                if (!Prm.Exists(PrmKeys.SpModulesPos))
                    Prm.CreateIntegerParam(PrmKeys.SpModulesPos, _fGroups.spModuleInfo.SplitterPosition);
                else
                    _fGroups.spModuleInfo.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpModulesPos);

                if (!Prm.Exists(PrmKeys.SpModulesHelp))
                    Prm.CreateIntegerParam(PrmKeys.SpModulesHelp, _fGroups.spModuleHelp.SplitterPosition);
                else
                    _fGroups.spModuleHelp.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpModulesHelp);

                //scripts form
                ////--------------------------------------------
                if (!Prm.Exists(PrmKeys.SpScriptPos))
                    Prm.CreateIntegerParam(PrmKeys.SpScriptPos, _fScripts.spScripts.SplitterPosition);
                else
                    _fScripts.spScripts.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpScriptPos);

                if (!Prm.Exists(PrmKeys.SpScriptInfoPos))
                    Prm.CreateIntegerParam(PrmKeys.SpScriptInfoPos, _fScripts.spScriptLeft.SplitterPosition);
                else
                    _fScripts.spScriptLeft.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpScriptInfoPos);

                if (!Prm.Exists(PrmKeys.SpScriptRight))
                    Prm.CreateIntegerParam(PrmKeys.SpScriptRight, _fScripts.spScriptRight.SplitterPosition);
                else
                    _fScripts.spScriptRight.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpScriptRight);


                //send mail form
                if (!Prm.Exists(PrmKeys.SpMailTemplatesPos))
                    Prm.CreateIntegerParam(PrmKeys.SpMailTemplatesPos, _fMails.scMailTemplates.SplitterPosition);
                else
                    _fMails.scMailTemplates.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpMailTemplatesPos);

                if (!Prm.Exists(PrmKeys.SpMailTemplateContentPos))
                    Prm.CreateIntegerParam(PrmKeys.SpMailTemplateContentPos, _fMails.scMailTemplateContent.SplitterPosition);
                else
                    _fMails.scMailTemplateContent.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpMailTemplateContentPos);

                if (!Prm.Exists(PrmKeys.SpMailTemplatesViewPos))
                    Prm.CreateIntegerParam(PrmKeys.SpMailTemplatesViewPos, _fMails.scMailTemplatesView.SplitterPosition);
                else
                    _fMails.scMailTemplatesView.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpMailTemplatesViewPos);
                //----------
                if (!Prm.Exists(PrmKeys.SpSendersLettersPos))
                    Prm.CreateIntegerParam(PrmKeys.SpSendersLettersPos, _fMails.scSendersLetters.SplitterPosition);
                else
                    _fMails.scSendersLetters.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpSendersLettersPos);

                if (!Prm.Exists(PrmKeys.SpMailListenerPos))
                    Prm.CreateIntegerParam(PrmKeys.SpMailListenerPos, _fMails.scMailListener.SplitterPosition);
                else
                    _fMails.scMailListener.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpMailListenerPos);

                if (!Prm.Exists(PrmKeys.SpListenerRulesPos))
                    Prm.CreateIntegerParam(PrmKeys.SpListenerRulesPos, _fMails.scListenerRules.SplitterPosition);
                else
                    _fMails.scListenerRules.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpListenerRulesPos);

                //work form               
                //if (!Prm.Exists(PrmKeys.SpLogMainPos))
                //    Prm.CreateIntegerParam(PrmKeys.SpLogMainPos, _fWork.spLogMain.SplitterPosition);
                //else
                //    _fWork.spLogMain.SplitterPosition = Prm.GetIntegerParam(PrmKeys.SpLogMainPos);
            }
        }

        private void FrmMainFormClosed(object sender, FormClosedEventArgs e)
        {
            Prm.SetStringParam("Skin", lafDefault.LookAndFeel.ActiveSkinName);

            //groups forms                                           
            Prm.SetIntegerParam(PrmKeys.SpMainPos, _fGroups.spGroups.SplitterPosition);
            Prm.SetIntegerParam(PrmKeys.SpGroupDescriptionPos, _fGroups.spProjectInfo.SplitterPosition);
            Prm.SetIntegerParam(PrmKeys.SpGroupsPos, _fGroups.spGroupInfo.SplitterPosition);
            Prm.SetIntegerParam(PrmKeys.SpModulesPos, _fGroups.spModuleInfo.SplitterPosition);
            Prm.SetIntegerParam(PrmKeys.SpModulesHelp, _fGroups.spModuleHelp.SplitterPosition);

            //scripts form
            Prm.SetIntegerParam(PrmKeys.SpScriptPos, _fScripts.spScripts.SplitterPosition);
            Prm.SetIntegerParam(PrmKeys.SpScriptInfoPos, _fScripts.spScriptLeft.SplitterPosition);
            Prm.SetIntegerParam(PrmKeys.SpScriptRight, _fScripts.spScriptRight.SplitterPosition);

            //send mail form
            Prm.SetIntegerParam(PrmKeys.SpMailTemplateContentPos, _fMails.scMailTemplateContent.SplitterPosition);
            Prm.SetIntegerParam(PrmKeys.SpMailTemplatesPos, _fMails.scMailTemplates.SplitterPosition);
            Prm.SetIntegerParam(PrmKeys.SpMailTemplatesViewPos, _fMails.scMailTemplatesView.SplitterPosition);

            Prm.SetIntegerParam(PrmKeys.SpSendersLettersPos, _fMails.scSendersLetters.SplitterPosition);
            Prm.SetIntegerParam(PrmKeys.SpMailListenerPos, _fMails.scMailListener.SplitterPosition);
            Prm.SetIntegerParam(PrmKeys.SpListenerRulesPos, _fMails.scListenerRules.SplitterPosition);

            //work form            
            //Prm.SetIntegerParam(PrmKeys.SpLogMainPos, _fWork.spLogMain.SplitterPosition);

            Prm.Save();

            //groups forms
            _fGroups.gvGroups.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvgroups.xml"));
            _fGroups.gvGroupInfo.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvgroupinfo.xml"));
            _fGroups.gvModules.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmodules.xml"));
            _fGroups.gvModuleInfo.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmoduleinfo.xml"));
            _fGroups.gvModuleParams.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmodulehelp.xml"));

            //scripts form
            _fScripts.gvScripts.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvscripts.xml"));
            _fScripts.gvScriptInfo.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvscriptsinfo.xml"));

            //mail daemons form
            _fMails.gvAccounts.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmailaccounts.xml"));
            _fMails.gvMailTemplates.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvmailtemplates.xml"));

            _fMails.gvSenders.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvsenders.xml"));
            _fMails.gvLetters.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvletters.xml"));
            _fMails.gvAllRules.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvallrules.xml"));
            _fMails.gvLetterRules.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "gvrules.xml"));

            //work form
            _fWork.tlWork.SaveLayoutToXml(String.Format("{0}\\{1}\\{2}", WorkDir, "Settings", "tlwork.xml"));
        }

        private void rgbiSkins_GalleryItemCheckedChanged(object sender, GalleryItemEventArgs e)
        {
            Prm.SetStringParam("Skin", lafDefault.LookAndFeel.ActiveSkinName);

            _stbGroupInfoScript.BackColor = Appearance.BackColor;
            Prm.Save();
        }

        public void SetActiveTab()
        {
            _fGroups.pnlMain.Visible = false;
            _fScripts.pnlMain.Visible = false;
            _fMails.pnlMain.Visible = false;
            _fWork.pnlMain.Visible = false;
            _fLog.pnlMain.Visible = false;

            _activePageIndex = ActivePageIdx.Main;

            foreach (RibbonPage rp in rbMain.Pages)
            {
                if (rp == rbMain.SelectedPage)
                    break;
                _activePageIndex++;
            }

            switch (_activePageIndex)
            {
                case ActivePageIdx.Main:
                    _fGroups.pnlMain.Visible = true;
                    RefreshGroups();
                    break;
                case ActivePageIdx.Work:
                    _fWork.pnlMain.Visible = true;
                    RefreshWork();
                    break;
                case ActivePageIdx.Scripts:
                    _fScripts.pnlMain.Visible = true;
                    RefreshScripts();
                    break;
                case ActivePageIdx.MailDaemons:
                    _fMails.pnlMain.Visible = true;
                    switch (_fMails.tcMails.SelectedTabPageIndex)
                    {
                        case (int)MailActivePageIdx.Accounts:
                            RefreshMailAccounts();
                            break;
                        case (int)MailActivePageIdx.Sender:
                            RefreshMailSendTemplates();
                            break;
                        case (int)MailActivePageIdx.Listener:
                            RefreshSenders();
                            break;
                        default:
                            break;
                    }
                    break;
                case ActivePageIdx.Log:
                    initLog(true);
                    _fLog.pnlMain.Visible = true;
                    _fLog.tcLogs.SelectedTabPage = _fLog.tpLogGeneral;
                    RefreshLog(_fLog.tcLogs.SelectedTabPage, true);
                    break;

                default:
                    break;
            }

            UpdateMainControlsState();
        }

        private void GridEnterLeave(object sender, EventArgs e)
        {
            UpdateMainControlsState();
        }

        private void rbMainSelectedPageChanged(object sender, EventArgs e)
        {
            SetActiveTab();
        }

        private void UpdateMainControlsState()
        {
            DataRow drs = _fScripts.gvScripts.GetDataRow(_fScripts.gvScripts.FocusedRowHandle);
            int currentScript = (drs == null) ? DM4Consts.DefaultNULLId : SysUtils.ConvertFromDBVal<int>(drs["scr_id"]);

            drs = _fGroups.gvGroups.GetDataRow(_fGroups.gvGroups.FocusedRowHandle);
            int currentGroup = (drs == null) ? DM4Consts.DefaultNULLId : SysUtils.ConvertFromDBVal<int>(drs[CnGroups.GrpId]);
            string currentGroupStatus = (drs == null) ? DM4Consts.TRUE : SysUtils.ConvertFromDBVal<string>(drs["grp_disabled"]);

            drs = _fGroups.gvModules.GetDataRow(_fGroups.gvModules.FocusedRowHandle);
            string currentModule = (drs == null) ? DM4Consts.SDefaultNULLId : SysUtils.ConvertFromDBVal<string>(drs["mod_code"]);

            //projects
            rbiAddProject.Enabled = _fGroups.dgGroups.Focused;

            rbiEditProject.Enabled = _fGroups.dgGroups.Focused &&
            currentGroup != DM4Consts.DefaultNULLId &&
            currentGroup != 1; //cant edit default project

            rbiDeleteProject.Enabled = _fGroups.dgGroups.Focused &&
            currentGroup != DM4Consts.DefaultNULLId &&
            currentGroup != 1;//cant delete default project

            rbiStartProjectOrModule.Enabled =
                //project
            (
            _fGroups.dgGroups.Focused &&
            currentGroup != DM4Consts.DefaultNULLId &&
            currentGroupStatus == DM4Consts.FALSE &&
            _fGroups.gvModules.RowCount > 0

            ) ||
                //module
            (
            _fGroups.dgModules.Focused &&
            currentModule != DM4Consts.SDefaultNULLId
            );

            beiStartModule.Enabled = rbiStartProjectOrModule.Enabled &&
            _fGroups.dgModules.Focused;

            //scripts
            rbiScriptStart.Enabled = _fScripts.dgScripts.Focused &&
            currentScript != DM4Consts.DefaultNULLId;

            rbiScriptCheck.Enabled = rbiScriptStart.Enabled;
            rbiScriptEdit.Enabled = rbiScriptStart.Enabled;
            rbiScriptDelete.Enabled = rbiScriptStart.Enabled;
            rbiScriptAdd.Enabled = _fScripts.dgScripts.Focused;


            //work
            string itemtype = "";
            string itemstatus = "";

            TreeListNode n = _fWork.tlWork.FocusedNode;
            if (n != null)
            {
                itemtype = (string)n.GetValue(2);
                itemstatus = (string)n.GetValue(6);
            }

            rbiWorkStop.Enabled =
              itemtype != "" &&
              itemstatus != "" && (
                (itemtype == "S" && itemstatus == "R") || //sessions
                (itemtype == "T" && itemstatus == "R") || //tasks
                (itemtype == "M" && itemstatus == "R")   //script
            );

            rbiWorkStart.Enabled =
              itemtype != "" &&
              itemstatus != "" && (
                (itemtype == "S" && itemstatus == "W") || //sessions
                (itemtype == "T" && itemstatus == "W") || //tasks
                (itemtype == "M" && itemstatus == "W")    //script
            );

            //mail daemons          
            rbiTestMail.Enabled = false;
            rbiStartMail.Enabled = false;
            rbiStopMail.Enabled = false;

            rbiAddMail.Enabled = false;
            rbiEditMail.Enabled = false;
            rbiDeleteMail.Enabled = false;


            int currentId;
            DevExpress.XtraGrid.GridControl gc = null;
            DevExpress.XtraGrid.Views.Grid.GridView gv = null;
            string columnIdName = "";
            switch (_activePageIndex)
            {
                case ActivePageIdx.MailDaemons:
                    {
                        switch (_fMails.tcMails.SelectedTabPageIndex)
                        {
                            case (int)MailActivePageIdx.Accounts:
                                drs = _fMails.gvAccounts.GetDataRow(_fMails.gvAccounts.FocusedRowHandle);
                                gc = _fMails.dgAccounts;
                                currentId = (drs == null) ? DM4Consts.DefaultNULLId : SysUtils.ConvertFromDBVal<int>(drs[CnMailAccounts.Id]);
                                rbiAddMail.Enabled = gc.Focused;
                                rbiEditMail.Enabled = gc.Focused && currentId != DM4Consts.DefaultNULLId;
                                rbiDeleteMail.Enabled = gc.Focused && currentId != DM4Consts.DefaultNULLId;
                                break;

                            case (int)MailActivePageIdx.Sender:
                                rbiTestMail.Enabled = Dm4Core.GetDaemonStatus(DM4.MailSenderConsts.ModuleCode) == DaemonStatus.Run;
                                rbiStartMail.Enabled = Dm4Core.GetDaemonStatus(DM4.MailSenderConsts.ModuleCode) == DaemonStatus.Stop;
                                rbiStopMail.Enabled = Dm4Core.GetDaemonStatus(DM4.MailSenderConsts.ModuleCode) == DaemonStatus.Run;

                                drs = _fMails.gvMailTemplates.GetDataRow(_fMails.gvMailTemplates.FocusedRowHandle);
                                gc = _fMails.dgMailTemplates;
                                currentId = (drs == null) ? DM4Consts.DefaultNULLId : SysUtils.ConvertFromDBVal<int>(drs[CnMailSendTemplate.Id]);
                                rbiAddMail.Enabled = gc.Focused;
                                rbiEditMail.Enabled = gc.Focused && currentId != DM4Consts.DefaultNULLId;
                                rbiDeleteMail.Enabled = gc.Focused && currentId != DM4Consts.DefaultNULLId;
                                break;
                            case (int)MailActivePageIdx.Listener:
                                rbiTestMail.Enabled = Dm4Core.GetDaemonStatus(DM4.MailListenerConsts.ModuleCode) == DaemonStatus.Run;
                                rbiStartMail.Enabled = Dm4Core.GetDaemonStatus(DM4.MailListenerConsts.ModuleCode) == DaemonStatus.Stop;
                                rbiStopMail.Enabled = Dm4Core.GetDaemonStatus(DM4.MailListenerConsts.ModuleCode) == DaemonStatus.Run;


                                drs = _fMails.gvAllRules.GetDataRow(_fMails.gvAllRules.FocusedRowHandle);
                                int ruleId = (drs == null) ? DM4Consts.DefaultNULLId : SysUtils.ConvertFromDBVal<int>(drs[CnMailRules.Id]);

                                drs = _fMails.gvLetters.GetDataRow(_fMails.gvLetters.FocusedRowHandle);
                                int letterId = (drs == null) ? DM4Consts.DefaultNULLId : SysUtils.ConvertFromDBVal<int>(drs[CnMailLetters.Id]);

                                _fMails.btnAddLetterRule.Enabled = ruleId != DM4Consts.DefaultNULLId && letterId != DM4Consts.DefaultNULLId;


                                drs = _fMails.gvLetterRules.GetDataRow(_fMails.gvLetterRules.FocusedRowHandle);
                                int mailRuleId = (drs == null) ? DM4Consts.DefaultNULLId : SysUtils.ConvertFromDBVal<int>(drs[CnMailRules.Id]);
                                _fMails.btnDeleteRule.Enabled = mailRuleId != DM4Consts.DefaultNULLId;

                                if (_fMails.gcSenders.Focused)
                                {
                                    gc = _fMails.gcSenders;
                                    gv = _fMails.gvSenders;
                                    columnIdName = CnMailSenders.Id;
                                }
                                else
                                    if (_fMails.gcLetters.Focused)
                                    {
                                        gc = _fMails.gcLetters;
                                        gv = _fMails.gvLetters;
                                        columnIdName = CnMailLetters.Id;
                                    }
                                    else
                                        if (_fMails.gcLetterRules.Focused)
                                        {
                                            rbiAddMail.Enabled = false;
                                            rbiEditMail.Enabled = false;
                                            rbiDeleteMail.Enabled = false;
                                            //gc = _fMails.gcRules;
                                            //gv = _fMails.gvRules;
                                            //columnIdName = CnMailRules.Id;
                                        }
                                        else
                                            if (_fMails.gcAllRules.Focused)
                                            {
                                                gc = _fMails.gcAllRules;
                                                gv = _fMails.gvAllRules;
                                                columnIdName = CnMailRules.Id;
                                            }

                                if (gv != null && gc != null && !String.IsNullOrEmpty(columnIdName))
                                {
                                    drs = gv.GetDataRow(gv.FocusedRowHandle);
                                    currentId = (drs == null) ? DM4Consts.DefaultNULLId : SysUtils.ConvertFromDBVal<int>(drs[columnIdName]);
                                    rbiAddMail.Enabled = gc.Focused;
                                    rbiEditMail.Enabled = gc.Focused && currentId != DM4Consts.DefaultNULLId;
                                    rbiDeleteMail.Enabled = gc.Focused && currentId != DM4Consts.DefaultNULLId;
                                }

                                break;
                            default:
                                break;
                        }
                    }
                    break;
                default:
                    break;
            }
        }

        private void BeginWait()
        {
            _waitRequestCount++;
            if (_waitRequestCount != 1)
                return;

            Action<object> action = DoWait;

            _waitCTS = new CancellationTokenSource();
            _wait = new Task(action, _waitCTS.Token, _waitCTS.Token);

            _wait.Start();
        }

        private void EndWait()
        {
            _waitRequestCount--;
            if (_waitRequestCount > 0)
                return;

            _waitCTS.Cancel();
            _waitRequestCount = 0;

            Task.WaitAny(_wait);
            TopMost = true;
            TopMost = false;
        }

        private void DoWait(object prm)
        {
            CancellationToken ct = (CancellationToken)prm;

            using (WaitForm frm = new WaitForm())
            {
                frm.Show();
                Application.DoEvents();

                while (!ct.IsCancellationRequested)
                    Thread.Sleep(10);

                frm.Close();
            }
        }

        private void rbiStartProjectOrModule_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            DataRow drs = _fGroups.gvGroups.GetDataRow(_fGroups.gvGroups.FocusedRowHandle);
            int currentGroup = (drs == null) ? DM4Consts.DefaultNULLId : SysUtils.ConvertFromDBVal<int>(drs[CnGroups.GrpId]);
            string currentGroupStatus = (drs == null) ? DM4Consts.TRUE : SysUtils.ConvertFromDBVal<string>(drs["grp_disabled"]);
            int defaultgroupscript = (drs == null || drs["grp_script"] is DBNull) ? DM4Consts.DefaultNULLId : SysUtils.ConvertFromDBVal<int>(drs["grp_script"]);

            drs = _fGroups.gvModules.GetDataRow(_fGroups.gvModules.FocusedRowHandle);
            string currentModule = (drs == null) ? DM4Consts.SDefaultNULLId : SysUtils.ConvertFromDBVal<string>(drs["mod_code"]);

            #region формирование параметров
            Dictionary<string, ParamEntry> modParams = new Dictionary<string, ParamEntry>();
            try
            {
                if (beiStartModule.EditValue != null && beiStartModule.EditValue.ToString() != "")
                    Array.ForEach(((string)(beiStartModule.EditValue)).Split(','), param =>
                    {
                        modParams.Add((param.Split('=')[0]).ToUpperInvariant().Trim(), new ParamEntry(param.Split('=')[1].Trim()));
                    });
            }
            catch 
            {
                MessageBox.Show(this, "Parameters is bad", DmConsts.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            #endregion

            if (//project                                                           
            _fGroups.dgGroups.Focused &&
            currentGroup != DM4Consts.DefaultNULLId &&
            currentGroupStatus == DM4Consts.FALSE
            )
            {
                if (MessageBox.Show(this, "Run selected group?", "Run group",
                MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
                    return;

                OperationResult or = new OperationResult();

                if (defaultgroupscript != DM4Consts.DefaultNULLId) //run default group script
                    or = RunScript(defaultgroupscript);
                else
                {
                    //XMLInfo xi = Dm4Srv.GetModulesList(currentGroup);
                    //DataTable moduleAll = XMLInfo.FillTable(xi);
                    //Dictionary<string, string> moduleAllDic = sscore.Utils.ComboUtils.DataTableToDict(moduleAll, "mod_code", "mod_disabled");
                    Dictionary<string, string> moduleRunDic = ComboUtils.DataTableToDict(DtModules, "mod_code", "mod_disabled");
                    List<string> modRun = (from mod in moduleRunDic
                                           where mod.Value != DM4Consts.TRUE
                                           select mod.Key).ToList();
                    if (modRun.Count > 0)
                        or = RunScript(modCode: modRun.ToArray(), modParams: StringUtils.ParamsToString(modParams));
                    else
                        MessageBox.Show(this, "Run count module = 0", DmConsts.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                if (or.Result != DM4Consts.Ok)
                    MessageBox.Show(this, or.Message, DmConsts.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
                else
                    MessageBox.Show(this, "Complete!", "Run Project", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
                if (//module                                                  
                _fGroups.dgModules.Focused &&
                currentModule != DM4Consts.SDefaultNULLId
                )
                {
                    if (MessageBox.Show(this, "Run selected module?", "Run module",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
                        return;

                    //generate script with params from beiStartModule.EditValue
                    OperationResult or = RunScript(modCode: currentModule, modParams: StringUtils.ParamsToString(modParams));
                    if (or.Result != DM4Consts.Ok)
                        MessageBox.Show(this, or.Message, DmConsts.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    else
                        MessageBox.Show(this, "Complete!", "Run module", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
        }

        private void iAbout_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            using (FrmAbout frm = new FrmAbout())
            {
                frm.lblVersion.Text = String.Format("Version {0}", _version);
                frm.ShowDialog();
            }
                
        }

        private void rbiShutdownItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            if (MessageBox.Show(this, "REALLY SHUTDOWN SERVER?", "Shutdown server",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
                return;
        }

    }
}
